<template>
  <div v-loading.fullscreen.lock="fullscreenLoading" class="h-full graph">
    <GraphHeader
      v-model:tagGraph="tagGraph"
      v-model:documentId="id"
      :parent-id="parentId"
      :tagConfig="tagConfigData"
      :zoomRate="zoomRate"
      :mmPxRatio="mmPxRatio"
      :bgImgFileName="bgImgFileName"
      :backgroundImageBase4="backgroundImageBase4"
      :bgImgPrint="bgImgPrint"
      :canvasRatio="canvasRatio"
      @saveSetting="handleSaveSetting"
      @clearActiveRef="
        () => {
          activeRef = null;
        }
      "
    />

    <div class="graph-content">
      <div class="graph-content-model">
        <div
          v-for="(item, index) in nodeModelList"
          :key="index"
          class="graph-content-model-item"
          @click="handleAddNode(item.key)"
        >
          <iconifyIconOnline :icon="item.icon" class="text-[30px] mr-2" />
        </div>
      </div>
      <div ref="windowRef" class="graph-content-graph">
        <SketchRuler
          :key="SketchRulerKey"
          :lang="sketchRulerData.lang"
          :thick="sketchRulerData.thick"
          :scale="sketchRulerData.scale"
          :width="sketchRulerData.width"
          :height="sketchRulerData.height"
          :startX="sketchRulerData.startX"
          :startY="sketchRulerData.startY"
          :shadow="sketchRulerData.shadow"
          :horLineArr="sketchRulerData.lines.h"
          :verLineArr="sketchRulerData.lines.v"
          :cornerActive="true"
        />
        <div
          id="screens"
          ref="screensRef"
          class="graph-content-screen"
          @wheel="handleWheel"
          @scroll="handleScroll"
        >
          <div ref="containerRef" class="graph-content-container">
            <canvas id="c" ref="canvasRef" />
          </div>
        </div>
      </div>
      <div class="graph-content-form">
        <div class="graph-content-form-header">属性</div>
        <component
          :is="activeRef"
          v-model:tagGraph="tagGraph"
          :zoomRate="zoomRate"
          :mmPxRatio="mmPxRatio"
          :canvasRatio="canvasRatio"
          style="padding: 10px 20px"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import dayjs from "dayjs";
import nodeModelList from "./components/module/index.js";
import iconifyIconOnline from "@/components/ReIcon/src/iconifyIconOnline";
import TagGraph from "@/utils/tagGraph.js";
import GraphHeader from "./components/graphHeader/index.vue";
import SketchRuler from "@/components/SketchRuler/sketchRuler.vue";
import { ElLoading } from "element-plus";
import { useRoute, useRouter } from "vue-router";
import { getDetail } from "@/api/tagGraph";
import { generateBarcode, generateQRCode } from "@/utils/code/code";
import { ref, reactive, onMounted, nextTick, onBeforeUnmount } from "vue";
import { urlToBase64 } from "@pureadmin/utils";

let initData = {};
let mmPxRatio = ref(3.75); // mm转px比率
let canvasRatio = ref(1.01); // 误差值
let mmWidth, mmHeight, pxWidth, pxHeight, viewportTransform;
let zoomRate = ref(1);
let bgImgFileName = ref("");
let backgroundImageBase4 = ref("");
let bgImgPrint = ref("no");

const route = useRoute();
const id = ref(route.query.id || null);
const parentId = route.query.parentId;
const tagConfigData = ref(null);
const fullscreenLoading = ref(false);
let tagGraph = reactive({});
let activeRef = ref(null);
let windowRef = ref(null);
let canvasRef = ref(null);
let screensRef = ref(null);
let containerRef = ref(null);
let SketchRulerKey = ref(0);

function parseConfig(config) {
  try {
    return JSON.parse(config.replaceAll("\\\\", "\\"));
  } catch (error) {
    console.error("Failed to parse config:", error);
    return {};
  }
}

function handleInitParams(config, canvasData = {}) {
  if (config) initParams(config, canvasData);
  tagConfigData.value = config;
}

// 处理保存标签设置
const router = useRouter();
const handleSaveSetting = async id => {
  router.replace({
    name: route.name, // 保持当前路由名称
    query: { ...route.query, id } // 合并新的查询参数
  });
  tagGraph.canvas.dispose();
  tagGraph.canvas = null;
  initCanvas(id);
};
const queryDetail = async id => {
  try {
    if (route.query.id || id) {
      const {
        data: { canvasData, tagConfig }
      } = await getDetail({ id });

      bgImgFileName.value = parseConfig(canvasData).bgImgFileName;
      bgImgPrint.value = parseConfig(canvasData).bgImgPrint;
      backgroundImageBase4.value = parseConfig(canvasData).backgroundImage?.src;
      initData = canvasData ? parseConfig(canvasData) : parseConfig(tagConfig);
      handleInitParams(parseConfig(tagConfig), initData);
    } else {
      const queryData = { ...route.query, tagName: route.query.name };
      handleInitParams(queryData);
    }
  } catch (error) {
    console.error("Failed to fetch detail:", error);
  }
};
const initParams = (tagConfig, canvasData = {}) => {
  zoomRate.value = tagConfig?.zoomRate || 1;
  mmWidth = tagConfig.width;
  mmHeight = tagConfig.height;
  pxWidth = mmWidth * mmPxRatio.value * canvasRatio.value;
  pxHeight = mmHeight * mmPxRatio.value * canvasRatio.value;
  if (canvasData.viewportTransform && canvasData.zoomRate) {
    viewportTransform = canvasData.viewportTransform[0] / canvasData.zoomRate;
  } else if (tagConfig.viewportTransform && tagConfig.zoomRate) {
    viewportTransform = tagConfig.viewportTransform[0] / tagConfig.zoomRate;
  } else {
    viewportTransform = mmHeight / 80;
  }
};

onMounted(async () => {
  await initCanvas(id.value);
});

const initCanvas = async id => {
  const loading = ElLoading.service({
    lock: true,
    text: "加载中..."
  });
  await queryDetail(id);
  tagGraph = new TagGraph("c", initData, () => {
    initSketchRuler();
    loading.close();
  });
  tagGraph.getCanvas().on("mouse:down", () => {
    let activeObject = tagGraph.getActiveObject();
    nextTick(() => {
      activeRef.value = nodeModelList.find(
        item => item.key == activeObject?.componentType
      )?.component;
    });
  });
};

onBeforeUnmount(() => {
  tagGraph = null;
});

const handleAddNode = key => {
  switch (key) {
    case "text":
      handleChangeActiveNode(tagGraph.addIText("123"));
      break;
    case "line":
      handleChangeActiveNode(tagGraph.addLine());
      break;
    case "image":
      handleUploadImage();
      break;
    case "rect":
      handleChangeActiveNode(tagGraph.addRectangle());
      break;
    case "ellipse":
      handleChangeActiveNode(tagGraph.addEllipse());
      break;
    case "qrcode":
      initQrcode();
      break;
    case "barcode":
      initBarcode();
      break;
    case "date":
      handleChangeActiveNode(
        tagGraph.addText(dayjs(new Date()).format("YYYY年MM月DD日"))
      );
      break;
    case "tableGroup":
      tagGraph.addTable(3, 3, 100, 50);
      break;
    default:
      break;
  }
};
//切换选中的节点
const handleChangeActiveNode = activeNode => {
  if (activeNode) {
    activeRef.value = nodeModelList.find(
      item => item.key == activeNode?.componentType
    )?.component;
  } else {
    activeRef.value = {};
  }
};
//从本地上传图片
const handleUploadImage = () => {
  const input = document.createElement("input");
  input.type = "file";
  input.accept = "image/*";
  input.onchange = e => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onload = e => {
      urlToBase64(e.target.result, "image/png").then(res => {
        tagGraph.addBase64Image(res);
      });
    };
    reader.readAsDataURL(file);
  };
  input.click();
};
//初始化二维码
const initQrcode = () => {
  generateQRCode("qrcode", "123456789")
    .then(base64 => {
      tagGraph.addqrCodeImage(base64).then(img => {
        handleChangeActiveNode(img);
      });
    })
    .catch(err => console.error(err));
};
//初始化条形码
const initBarcode = () => {
  generateBarcode("code128", "0123456789", "bottom", "SimHei")
    .then(base64 =>
      tagGraph.addbarCodeImage(base64).then(img => {
        handleChangeActiveNode(img);
      })
    )
    .catch(err => console.error(err));
};
// 初始化绘制窗口和标尺
const initSketchRuler = () => {
  // 获取滚动条宽度
  sketchRulerData.scrollBarWidth = getScrollBarWidth();
  // 设置canvas-container元素的初始属性
  const canvasContainer = document.querySelector(
    ".graph-content-container>div"
  );
  canvasContainer.style.transformOrigin = "0 0";
  canvasContainer.style.position = "absolute";
  canvasContainer.style.left = "50%";

  setTimeout(() => {
    // canvas初始化自适应放缩
    initAutoScale(canvasContainer, windowRef.value);

    // canvas滚动居中
    screensRef.value.scrollLeft =
      containerRef.value.getBoundingClientRect().width / 2 -
      screensRef.value.getBoundingClientRect().width / 2 +
      canvasContainer.getBoundingClientRect().width / 2;

    // 监听window窗口变化
    resizeObserver.observe(windowRef.value);
    // 强制更新SketchRuler
    SketchRulerKey.value++;
  }, 0);
};

// canvas初始化自适应放缩
const initAutoScale = (canvasDom, windowDom) => {
  let windowWidth = windowDom.clientWidth;
  let windowHeight = windowDom.clientHeight;

  if (windowWidth / windowHeight > pxWidth / pxHeight) {
    // 高度适应窗口
    let visibleHeight =
      windowHeight - sketchRulerData.scrollBarWidth - sketchRulerData.thick;
    let targetHeight = visibleHeight * 0.92;
    let canvasTop = visibleHeight * 0.04 + sketchRulerData.thick;
    zoomRate.value = targetHeight / pxHeight;
    sketchRulerData.scale =
      zoomRate.value * mmPxRatio.value * canvasRatio.value;
    canvasDom.style.top = `${canvasTop}px`;
    resizeScreen();
  } else {
    // 宽度视屏窗口
    let visibleWidth =
      windowWidth - sketchRulerData.scrollBarWidth - sketchRulerData.thick;
    let targetWidth = visibleWidth * 0.92;
    zoomRate.value = targetWidth / pxWidth;
    sketchRulerData.scale =
      zoomRate.value * mmPxRatio.value * canvasRatio.value;
    let visibleHeight =
      windowHeight - sketchRulerData.scrollBarWidth - sketchRulerData.thick;
    let canvasTop =
      visibleHeight / 2 +
      sketchRulerData.thick -
      (pxHeight * zoomRate.value) / 2;
    canvasDom.style.top = `${canvasTop}px`;
    resizeScreen();
  }
};

// 视图根据放缩比例变化
const resizeScreen = () => {
  let currentTransform = viewportTransform * zoomRate.value;
  tagGraph.canvas.zoomRate = zoomRate.value || 1;
  tagGraph.canvas.viewportTransform[0] = currentTransform;
  tagGraph.canvas.viewportTransform[3] = currentTransform;
  tagGraph.canvas.width = pxWidth * zoomRate.value;
  tagGraph.canvas.height = pxHeight * zoomRate.value;
  tagGraph.loadFromJSON(tagGraph.save());
  tagGraph.canvas.setDimensions({
    width: tagGraph.canvas.width,
    height: tagGraph.canvas.height
  });
};

// 绘制区域的窗口和标尺
const sketchRulerData = reactive({
  scale: 1,
  width: 0,
  height: 0,
  startX: 0,
  startY: 0,
  lines: {
    h: [],
    v: []
  },
  thick: 20,
  lang: "zh-CN",
  isShowRuler: true,
  isShowReferLine: true,
  scrollBarWidth: 0,
  shadow: {
    x: 0,
    y: 0,
    width: pxWidth,
    height: pxHeight
  }
});

// 监听窗口变化，实时改变窗口尺寸
const resizeObserver = new ResizeObserver(entries => {
  entries.forEach(entry => {
    const { width, height } = entry.contentRect;
    sketchRulerData.width = width - sketchRulerData.scrollBarWidth;
    sketchRulerData.height = height - sketchRulerData.scrollBarWidth;
  });
});

// 监听窗口滚动
let handleScroll = () => {
  const screensRect = document
    .querySelector("#screens")
    .getBoundingClientRect();
  const canvasRect = document.querySelector("#c").getBoundingClientRect();
  // 标尺开始的刻度
  const startX =
    (screensRect.left + sketchRulerData.thick - canvasRect.left) /
    sketchRulerData.scale;
  const startY =
    (screensRect.top + sketchRulerData.thick - canvasRect.top) /
    sketchRulerData.scale;
  sketchRulerData.startX = startX;
  sketchRulerData.startY = startY;
};
// 监听窗口缩放
let handleWheel = e => {
  if (e.ctrlKey || e.metaKey) {
    e.preventDefault();
    const nextScale = parseFloat(
      Math.max(0.2, sketchRulerData.scale - e.deltaY / 500).toFixed(2)
    );
    sketchRulerData.scale = nextScale;
    zoomRate.value = sketchRulerData.scale / mmPxRatio.value;
    resizeScreen();
  }

  nextTick(() => {
    handleScroll();
  });
};

// 获取滚动条宽度
let getScrollBarWidth = () => {
  let scrollbarWidth = 0;
  const outer = document.createElement("div");
  outer.style.visibility = "hidden";
  outer.style.overflow = "scroll"; // 这里使用 'scroll' 会产生滚动条
  outer.style.width = "100px"; // 宽度可以自定义
  outer.style.height = "0px";
  document.body.appendChild(outer);
  const inner = document.createElement("div");
  inner.style.width = "100%";
  outer.appendChild(inner);
  scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
  outer.parentNode.removeChild(outer);
  return scrollbarWidth;
};
</script>

<style lang="scss" scoped>
@import url("./public/scss/index.scss");

.graph-content-graph {
  position: relative;
}

.graph-content-screen {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: auto;
}

.graph-content-container {
  position: absolute;
  width: 5000px;
  height: 3000px;
  background: #d7d9db;
}

#c {
  position: absolute;
  width: 160px;
  height: 200px;
  background: rgb(255 255 255);
  transform-origin: 50% 0;
}
</style>
